//-----------------------------------------------------------------------
// <copyright file="MLCodeForm.cs" company="MAPILab Ltd">
//     Copyright (c) MAPILab Ltd.  All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
namespace MAPILab.SharePoint.Explorer.CodeForm
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Collections.Specialized;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.Drawing;
    using System.IO;
    using System.Text;
    using System.Text.RegularExpressions;
    using System.Threading;
    using System.Windows.Forms;
    using MAPILab.SharePoint.Explorer;
    using MAPILab.SharePoint.Explorer.CodeForm.CodeTemplates;
    using MAPILab.SharePoint.Explorer.CodeForm.SyntaxHighlightingTextBox;
    using MAPILab.SharePoint.Explorer.Docking;
    using MAPILab.SharePoint.Explorer.Information;
    using MAPILab.SharePoint.Explorer.Managment;
    using MAPILab.SharePoint.Explorer.ObjectBrowser;
    using MAPILab.SharePoint.Explorer.Properties;
    using MAPILab.SharePoint.Explorer.Utilities;
    using MAPILab.SharePoint.Explorer.Utilities.ScriptRunner;

    /// <summary>
    /// Form for coding, debug and compile scripts
    /// </summary>
    public partial class MLCodeForm : DockContent
    {
        #region Fields

        /// <summary>
        /// Thread to abort backGroundWorker
        /// </summary>
        Thread mThread = null;

        /// <summary>
        /// TraceListener item 
        /// </summary>
        private MLTraceListener listener;

        /// <summary>
        /// Loaded file name
        /// </summary>
        private string loadFileName = String.Empty;

        /// <summary>
        /// File with source code name
        /// </summary>
        private string codeFileName = String.Empty;

        /// <summary>
        /// Main form item
        /// </summary>
        private MLMainForm mainForm;

        /// <summary>
        /// Object browser for result
        /// </summary>
        private MLObjectBrowser resultObjectBrowser;

        /// <summary>
        /// Dictionary with parameters
        /// </summary>
        private Dictionary<string, object> parametersObject;

        /// <summary>
        /// Parameters for main function
        /// </summary>
        private List<object> mainParams;

        /// <summary>
        /// Is saved flag
        /// </summary>
        private bool IsSaved = false;

        /// <summary>
        /// Default language of source code
        /// </summary>
        private CodeLanguage codeLanguage;

        /// <summary>
        /// Item to display in object browser
        /// </summary>
        private MLBrowser browser = new MLBrowser();

        /// <summary>
        /// Delegate for MultiThread write to contorol
        /// </summary>
        /// <param name="s"></param>
        private delegate void MultiThreadWrite(string s);

        /// <summary>
        /// Messege to get line by its number
        /// </summary>
        private const int EM_GETLINE = 0xc4;

        #endregion

        #region Enums

        /// <summary>
        /// Type of file
        /// </summary>
        private enum FileType
        {
            New,
            Exist
        }

        #endregion

        #region Properties

        /// <summary>
        /// Get and set main form item
        /// </summary>
        public MLMainForm MainForm
        {
            get { return this.mainForm; }
            set { this.mainForm = value; }
        }

        /// <summary>
        /// Get and set default langueage of source code
        /// </summary>
        internal CodeLanguage CodeLanguage
        {
            get { return this.codeLanguage; }
            set { this.codeLanguage = value; }
        }

        /// <summary>
        /// Get and set parameters dictionary
        /// </summary>
        public Dictionary<string, object> ParametersObject
        {
            get { return parametersObject; }
            set { parametersObject = value; }
        }

        /// <summary>
        /// Get and set name of source code file
        /// </summary>
        public string CodeFileName
        {
            get { return codeFileName; }
            set { codeFileName = value; }
        }

        /// <summary>
        /// Form that opens this form
        /// </summary>
        public MLObjectBrowser ResultObjectBrowser
        {
            get { return resultObjectBrowser; }
            set { resultObjectBrowser = value; }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor
        /// </summary>
        public MLCodeForm()
        {
            InitializeComponent();
        }
        
        /// <summary>
        /// Overrided constructor
        /// </summary>
        /// <param name="fileName">file name</param>
        public MLCodeForm(string fileName)
            : this()
        {
            loadFileName = fileName;
        }

        #endregion

        #region Events

        /// <summary>
        /// Loading form
        /// </summary>
        /// <param name="sender">event sender</param>
        /// <param name="e">event parameter</param>
        private void CodeForm_Load(object sender, EventArgs e)
        {
            // create Trace listener item
            listener = new MLTraceListener();
            listener.CodeForm = this;

            //set the form tab text
            if (codeLanguage == CodeLanguage.VBNet)
                this.Text = "VB.Net Code Window";
            else
                this.Text = "C# Code Window";

            //Set buttons
            LockButtons(true);

            // Set the SyntaxHighlighting for current code language
            SetSyntaxHighlighting();

            // Set the default code template for current code language
            SetTemplate();

            //set word wrap
            codeBox.WordWrap = Settings.Default.WordWrap;
            wordWrapToolStripMenuItem.Checked = Settings.Default.WordWrap;

            this.wordWrapToolStripMenuItem.CheckedChanged += new EventHandler(WordWrap_Change);
            this.outputBox.DoubleClick += new EventHandler(OutputBox_DoubleClick);
            this.TextChanged += new EventHandler(CodeForm_TextChanged);            
        }

        /// <summary>
        /// Manage texts of the code form and the main form
        /// </summary>
        /// <param name="sender">event sender</param>
        /// <param name="e">event parameter</param>
        private void CodeForm_TextChanged(object sender, EventArgs e)
        {
            if (this.Text == String.Empty || this.Text == null)
            {
                //set the form tab text
                if (codeLanguage == CodeLanguage.VBNet)
                    this.Text = "VB.Net Code Window";
                else
                    this.Text = "C# Code Window";
            }
            mainForm.Text = Properties.Resources.ProductName + " :: " + this.Text;
        }

        /// <summary>
        /// Show error on double click
        /// </summary>
        /// <param name="sender">event sender</param>
        /// <param name="e">event parameter</param>
        private void OutputBox_DoubleClick(object sender, EventArgs e)
        {
            ShowError();
        }

        /// <summary>
        /// On code box selection changed
        /// </summary>
        /// <param name="sender">event sender</param>
        /// <param name="e">event parameter</param>
        private void CodeBox_SelectionChanged(object sender, EventArgs e)
        {
            GetCoursorPosition();
        }

        /// <summary>
        /// Set code box word wrap
        /// </summary>
        /// <param name="sender">event sender</param>
        /// <param name="e">event parameter</param>
        private void WordWrap_Change(object sender, EventArgs e)
        {
            this.codeBox.WordWrap = !this.codeBox.WordWrap;
            wordWrapToolStripMenuItem.Checked = this.codeBox.WordWrap;
            Settings.Default.WordWrap = this.codeBox.WordWrap;
            Settings.Default.Save();
        }

        /// <summary>
        /// Help
        /// </summary>
        /// <param name="sender">event sender</param>
        /// <param name="hlpevent">event parameter</param>
        private void ShowHelp(object sender, HelpEventArgs hlpevent)
        {
            MLHtmlHelper.ShowTopic(this, "explorer", 113);
        }

        /// <summary>
        /// Compile button click
        /// </summary>
        /// <param name="sender">event sender</param>
        /// <param name="e">event parameter</param>
        private void CompileButton_Click(object sender, EventArgs e)
        {
            LockButtons(false);

            if (!Settings.Default.UseAsyncMethod)
            {
                StopButton.Enabled = false;
                stopMenuItem.Enabled = false;
            }

            CompileScript();

            LockButtons(true);
        }

        /// <summary>
        /// Run Script
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void RunButton_Click(object sender, EventArgs e)
        {
            LockButtons(false);

            if (!Settings.Default.UseAsyncMethod)
            {
                StopButton.Enabled = false;
                stopMenuItem.Enabled = false;
            }

            RunScript();
        }

        /// <summary>
        /// Save existed script
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            IsSaved = false;
            SaveFile(FileType.Exist);
        }

        /// <summary>
        /// Save script as new one
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void saveAsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            IsSaved = false;
            SaveFile(FileType.New);
        }

        /// <summary>
        /// Save stored script
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void saveAsStartupToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SaveAsStored();
        }

        /// <summary>
        /// Abort run method
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void StopButton_Click(object sender, EventArgs e)
        {
            if (mThread != null)
                mThread.Abort();
            LockButtons(true);
        }

        /// <summary>
        /// Work for BackGroundWorker
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void BackgroundRunner_DoWork(object sender, DoWorkEventArgs e)
        {
            if (e.Argument is string)
            {
                try
                {
                    mThread = Thread.CurrentThread;

                    MLExecutionResults executionResults = MLScriptRunner.Execute(e.Argument as string, References(), mainParams, codeLanguage);

                    BackGroundRunner.ReportProgress(99, executionResults);
                }
                catch (ThreadAbortException ex)
                {
                    Thread.ResetAbort();
                    BackGroundRunner.ReportProgress(99, ex);
                }
                catch (Exception ex)
                {
                    BackGroundRunner.ReportProgress(99, ex);
                }
                finally
                {
                    mThread = null;
                }
            }
        }

        /// <summary>
        /// On ProgressChange
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void BackgroundRunner_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            if (e.UserState is MLExecutionResults)
            {
                ProgressOnNonErrorsFind(e.UserState as MLExecutionResults);
            }
            else if (e.UserState is ThreadAbortException)
            {
                Write("\nStopped");
            }
            else if (e.UserState is Exception)
            {
                OpenBrowserWindow(new object[] { (e.UserState as Exception).InnerException }, "Exeption", true);
            }

            Trace.Listeners.Remove(listener);

            LockButtons(true);
        }

        /// <summary>
        /// Add new references
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void addToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                OpenFileDialog open = new OpenFileDialog();
                open.DefaultExt = "dll";
                open.Multiselect = true;
                open.Filter = "Unit Test Assembly Files (*.dll, *.exe)|*.dll;*.exe|All files (*.*)|*.*";
                if (open.ShowDialog() == DialogResult.OK)
                {
                    foreach (string fileName in open.FileNames)
                        referencesGrid.Rows.Add(fileName);
                }
            }
            catch (Exception ex)
            {
                ShowError(ex.Message);
            }
        }

        /// <summary>
        /// Remove references
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void removeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Point hitPoint = contextMenuStrip.Bounds.Location;
            Point pointToClient = referencesGrid.PointToClient(hitPoint);
            DataGridView.HitTestInfo hti = referencesGrid.HitTest(pointToClient.X, pointToClient.Y);

            if (hti != null && hti.RowIndex != -1 && hti.RowIndex != referencesGrid.NewRowIndex)
            {
                foreach (DataGridViewCell cell in referencesGrid.SelectedCells)
                {
                    referencesGrid.Rows[cell.RowIndex].Selected = true;
                }
                if (referencesGrid.SelectedCells.Count > 1 && referencesGrid.Rows[hti.RowIndex].Selected)
                {
                    try
                    {
                        for (int i = referencesGrid.Rows.Count - 1; i >= 0; i--)
                        {
                            if (referencesGrid.Rows[i].Selected)
                            {
                                referencesGrid.Rows.RemoveAt(i);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        ShowError(ex.Message);
                    }
                }
                else
                {
                    referencesGrid.Rows.RemoveAt(hti.RowIndex);
                }
            }
        }

        /// <summary>
        /// On context menu stripe open
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void contextMenuStrip_Opening(object sender, CancelEventArgs e)
        {
            Point hitPoint = contextMenuStrip.Bounds.Location;
            Point pointToClient = referencesGrid.PointToClient(hitPoint);
            DataGridView.HitTestInfo hti = referencesGrid.HitTest(pointToClient.X, pointToClient.Y);

            if (hti != null && hti.RowIndex != -1 && hti.RowIndex != referencesGrid.NewRowIndex)
            {
                removeToolStripMenuItem.Visible = true;
            }
            else
            {
                removeToolStripMenuItem.Visible = false;
            }
        }

        /// <summary>
        /// Cut selected text or line
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (codeBox.SelectedText == null)
                return;

            codeBox.SuspendLayout();

            if (!String.IsNullOrEmpty(codeBox.SelectedText))
            {
                Clipboard.SetText(codeBox.SelectedText);
                codeBox.SelectedText = String.Empty;
            }
            else
            {
                int line = codeBox.GetLineFromCharIndex(codeBox.GetFirstCharIndexOfCurrentLine());
                string str = codeBox.Lines[line];
                if (str != null && str != "")
                    Clipboard.SetText(str);
                codeBox.Select(codeBox.GetFirstCharIndexOfCurrentLine(), codeBox.Lines[line].Length + 1);
                codeBox.SelectedText = String.Empty;
            }

            codeBox.ResumeLayout();
        }

        /// <summary>
        /// Copy selected text or line
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void copyToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (codeBox.SelectedText == null)
                return;

            if (!String.IsNullOrEmpty(codeBox.SelectedText))
            {
                Clipboard.SetText(codeBox.SelectedText);
            }
            else
            {
                int line = codeBox.GetLineFromCharIndex(codeBox.GetFirstCharIndexOfCurrentLine());
                string str = codeBox.Lines[line];
                if (str != null && str != "")
                    Clipboard.SetText(str);
            }
        }

        /// <summary>
        /// Paste text
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void pasteToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (Clipboard.ContainsText())
                codeBox.SelectedText = Clipboard.GetText().TrimStart(new char[] { ' ' });
        }

        /// <summary>
        /// On edit Menu Stripe opening 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void editMenuStrip_Opening(object sender, CancelEventArgs e)
        {
            if (Clipboard.ContainsText() && runMenuItem.Enabled)
            {
                pasteToolStripMenuItem.Enabled = true;
            }
            else
            {
                pasteToolStripMenuItem.Enabled = false;
            }
        }

        /// <summary>
        /// On edit tool stripe menu item open
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void editToolStripMenuItem_DropDownOpening(object sender, EventArgs e)
        {
            if (Clipboard.ContainsText() && runMenuItem.Enabled)
            {
                pasteMenuItem.Enabled = true;
            }
            else
            {
                pasteMenuItem.Enabled = false;
            }

            redoToolStripMenuItem.Enabled = true;
            undoToolStripMenuItem.Enabled = true;

            if (!codeBox.CanRedo)
            {
                redoToolStripMenuItem.Enabled = false;
            }

            if (!codeBox.CanUndo)
            {
                undoToolStripMenuItem.Enabled = false;
            }
        }

        /// <summary>
        /// Undo changes
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void undoToolStripMenuItem_Click(object sender, EventArgs e)
        {
            codeBox.Undo();
        }

        /// <summary>
        /// redo changes
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void redoToolStripMenuItem_Click(object sender, EventArgs e)
        {
            codeBox.Redo();
        }

        #endregion

        #region Methods

        #region Template

        /// <summary>
        /// Generate code template
        /// </summary>
        private void SetTemplate()
        {
            try
            {
                if (ParametersObject == null)
                {
                    ParametersObject = new Dictionary<string, object>();
                }
                ParametersObject.Add("thisForm", this);
                ParametersObject.Add("browser", browser);
                    
                if (!string.IsNullOrEmpty(loadFileName))
                {
                    //Load source code from file
                    LoadCodeFile();
                }
                else
                {
                    //Create code template
                    MLBaseCodeTemplate codeTemplate = CreateCodeFile();

                    mainParams = codeTemplate.MainParameters;
                    parametersObject = codeTemplate.ParametersObject;

                    //Load Default references 
                    foreach (string defRefName in Settings.Default.references)
                    {
                        referencesGrid.Rows.Add(new string[] { defRefName });
                    }

                    //adding non default references
                    AddingNonDefaultReferences(codeTemplate.References);
                }                

                if (ParametersObject != null)
                {
                    MakeVarsTable();
                }

                codeBox.SelectionStart = 0;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Properties.Resources.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        /// <summary>
        /// Adding non default references in ReferencesGrid
        /// </summary>
        /// <param name="codeTemplate"></param>
        private void AddingNonDefaultReferences(StringCollection references)
        {
            foreach (string reference in references)
            {
                if (!Settings.Default.references.Contains(reference))
                {
                    referencesGrid.Rows.Add(new string[] { reference });
                }
            }
        }

        /// <summary>
        /// Create code template
        /// </summary>
        /// <returns></returns>
        private MLBaseCodeTemplate CreateCodeFile()
        {
            //Create new source code file
            MLBaseCodeTemplate codeTemplate;

            //create specific language template
            switch (codeLanguage)
            {
                case CodeLanguage.VBNet: codeTemplate = new MLVBNetCodeTemplate();
                    break;

                case CodeLanguage.CSharp:
                default: codeTemplate = new MLCSharpCodeTemplate();
                    break;
            }
            //add parameters object
            codeTemplate.ParametersObject = parametersObject;
            //add main parameters
            codeTemplate.MainParameters = mainParams;
            //add references
            StringCollection references = new StringCollection();
            foreach (DataGridViewRow refRow in referencesGrid.Rows)
            {
                try
                {
                    string refName = refRow.Cells[0].Value as string;
                    if (!String.IsNullOrEmpty(refName))
                    {
                        references.Add(refName);
                    }
                }
                catch
                {
                }
            }
            codeTemplate.References = references;

            //Generate code template
            codeBox.Text = codeTemplate.GenerateTemplate();
            return codeTemplate;
        }

        /// <summary>
        /// Loading code file
        /// </summary>
        private void LoadCodeFile()
        {
            try
            {
                using (StreamReader reader = new StreamReader(loadFileName))
                {
                    codeBox.Text = reader.ReadToEnd();

                    string commentMask = String.Empty;
                    if (codeLanguage == CodeLanguage.VBNet)
                        commentMask = @"'addref\<(?<addref>[^\>]+)\>";
                    else
                        commentMask = @"///addref\<(?<addref>[^\>]+)\>";

                    Regex regex = new Regex(commentMask);
                    MatchCollection refMatches = regex.Matches(codeBox.Text);

                    foreach (Match refMatch in refMatches)
                    {
                        string refName = refMatch.Groups["addref"].Value;
                        if (!string.IsNullOrEmpty(refName))
                        {
                            referencesGrid.Rows.Add(new string[] { refName });
                        }
                    }
                }

                codeFileName = loadFileName;
                this.Text = loadFileName.Remove(0, loadFileName.LastIndexOf('\\') + 1);
            }
            catch (Exception ex)
            {
                throw new NotImplementedException(ex.Message, ex.InnerException);
            }
        }

        /// <summary>
        /// Make list of all variables
        /// </summary>
        private void MakeVarsTable()
        {
            foreach (KeyValuePair<string, object> paramKeyValuePair in ParametersObject)
            {
                ListViewItem lvi = varsList.Items.Add(paramKeyValuePair.Key);

                if (paramKeyValuePair.Value != null)
                {
                    object paramValue = paramKeyValuePair.Value;

                    if (paramValue is MLMethodParameter)
                    {
                        paramValue = (paramValue as MLMethodParameter).MethodInfo;
                    }

                    lvi.SubItems.Add(paramValue.ToString());
                    lvi.SubItems.Add(MLUtils.GetTypeOutput(paramValue.GetType()));

                    Type paramType = paramValue.GetType();
                }
                else
                {
                    lvi.SubItems.Add("<null>");
                    lvi.SubItems.Add("<null>");
                }
            }
        }

        #endregion

        #region Run and Compile

        /// <summary>
        /// check and displey errors (warnings)
        /// </summary>
        /// <param name="errorsCollection">Collection of errors</param>
        /// <param name="warningsCollection">Collection of warning</param>
        private void CheckErrors(StringCollection errorsCollection, StringCollection warningsCollection)
        {
            //Write errors
            if (errorsCollection.Count > 0)
            {
                int i = 0;
                WriteLine("\n---------Errors--------");
                foreach (string error in errorsCollection)
                {
                    i++;
                    WriteLine(i.ToString() + " -> " + error);
                }
            }
            //Write warnings
            if (warningsCollection.Count > 0)
            {
                int i = 0;
                WriteLine("\n--------Warnings-------");
                foreach (string warning in warningsCollection)
                {
                    i++;
                    WriteLine(i.ToString() + " -> " + warning);
                }
            }

            WriteLine("\nCompile complete -- " + errorsCollection.Count.ToString() + " errors, " + warningsCollection.Count.ToString() + " warnings");
        }

        /// <summary>
        /// Compiling script
        /// </summary>
        private void CompileScript()
        {
            OutputClear();
            WriteLine("Build started...");

            StringCollection errorsCollection = new StringCollection();
            StringCollection warningsCollection = new StringCollection();

            try
            {
                MLCompilationResults compilationResults = MLScriptRunner.Compilation(codeBox.Text, References(), codeLanguage);
                errorsCollection = compilationResults.ErrorsCollection;
                warningsCollection = compilationResults.WarningsCollection;
            }
            catch (Exception ex)
            {
                errorsCollection.Add(ex.Message);
            }

            CheckErrors(errorsCollection, warningsCollection);
        }

        /// <summary>
        /// Run Script
        /// </summary>
        private void RunScript()
        {
            OutputClear();

            try
            {
                ExecuteMethodMain();
            }
            catch (Exception ex)
            {
                mainForm.DisplayException(ex);
            }
        }

        /// <summary>
        /// Execute main method
        /// </summary>
        /// <returns></returns>
        private void ExecuteMethodMain()
        {
            //Clean browser window properties before compile code 
            browser.DisplayMode = DisplayMode.Raw;
            browser.ReturnValue = null;
            browser.Text = null;

            WriteLine("Running method main...");
            Trace.Listeners.Add(listener);

            try
            {
                //Run script
                if (Settings.Default.UseAsyncMethod)
                {
                    BackGroundRunner.RunWorkerAsync(codeBox.Text);
                }
                else
                {
                    try
                    {
                        MLExecutionResults executionResults = MLScriptRunner.Execute(codeBox.Text, References(), mainParams, codeLanguage);

                        ProgressOnNonErrorsFind(executionResults);
                    }
                    catch (Exception ex)
                    {
                        OpenBrowserWindow(new object[] { ex.InnerException }, "Exeption", true);
                    }
                    finally
                    {
                        Trace.Listeners.Remove(listener);
                        LockButtons(true);
                    }
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }            
        }

        /// <summary>
        /// Progress work if non exeptions have been detected
        /// </summary>
        /// <param name="e">event argument</param>
        private void ProgressOnNonErrorsFind(MLExecutionResults executionResults)
        {
            MLBrowser result = null;
            StringCollection errorsCollection = new StringCollection();
            StringCollection warningsCollection = new StringCollection();

            result = executionResults.ReturnedObjects;
            errorsCollection = executionResults.ErrorsCollection;
            warningsCollection = executionResults.WarningsCollection;

            //Display errors
            CheckErrors(errorsCollection, warningsCollection);
            WriteLine("Operation complete!");

            if ((errorsCollection.Count == 0) && (result == null || result.ReturnValue == null))
            {
                WriteLine("Browser return <null>");
            }

            if ((result != null) && (result.ReturnValue != null))
            {
                //Choose the way to display object(s)
                object[] browsedObjects = null;
                if ((result.DisplayMode == DisplayMode.Raw) || !(result.ReturnValue is IEnumerable))
                {
                    browsedObjects = new object[] { result.ReturnValue };
                }
                else
                {
                    if (result.ReturnValue is object[])
                    {
                        browsedObjects = result.ReturnValue as object[];
                    }
                    else
                    {
                        IEnumerable collection = result.ReturnValue as IEnumerable;

                        //The number of objects in collection to display in expended mode
                        int number = 0;
                        foreach (object o in collection)
                        {
                            number++;
                        }                        

                        if (browsedObjects == null)
                            browsedObjects = new object[number];
                        int i = 0;
                        foreach (object o in collection)
                        {
                            browsedObjects[i] = o;
                            i++;
                        }                        
                    }
                }

                //Change the form text
                string text = String.Empty;
                if (result.Text == null)
                {
                    text = "Returned value: " + result.ReturnValue.ToString();
                }
                else
                {
                    text = result.Text;
                }

                OpenBrowserWindow(browsedObjects, text, result.OpenInNewWindow);
            }
        }


        /// <summary>
        /// Open browser window to dislay returned objects
        /// </summary>
        /// <param name="browsedObjects">Objects to display in browser window</param>
        /// <param name="text">Tab text of browser window</param>
        /// <param name="newWindow">Open  in new window</param>
        private void OpenBrowserWindow(object[] browsedObjects, string text, bool newWindow)
        {
            //MLObjectBrowser form = new MLObjectBrowser();
            if (resultObjectBrowser == null || newWindow)
            {
                if (resultObjectBrowser != null)
                {
                    resultObjectBrowser.PreviousForm = null;
                }

                resultObjectBrowser = new MLObjectBrowser();
                resultObjectBrowser.BrowsedObjects = browsedObjects;
                resultObjectBrowser.Text = text;                
                resultObjectBrowser.PreviousForm = this;
                

                //Display style
                if (mainForm.dockPanel.DocumentStyle == Docking.DocumentStyle.SystemMdi)
                {
                    resultObjectBrowser.MdiParent = MdiParent;
                    resultObjectBrowser.Show();
                }
                else
                {
                    resultObjectBrowser.Show(mainForm.dockPanel);
                }
            }
            else
            {
                resultObjectBrowser.BrowsedObjects = browsedObjects;
                resultObjectBrowser.Text = text;
                resultObjectBrowser.PreviousForm = this;

                resultObjectBrowser.MainForm = MdiParent as MLMainForm;
                
                resultObjectBrowser.Refresh();
            }
        }

        #endregion

        #region Save code file

        /// <summary>
        /// Saving created scrypt
        /// </summary>
        /// <param name="fileType"></param>
        private void SaveFile(FileType fileType)
        {
            try
            {
                string originText = codeBox.Text;
                StringBuilder scriptText = new StringBuilder(originText);
                StringBuilder insertRefText = new StringBuilder();

                //Add references as comments before script
                StringCollection references = References();

                string commentMask = String.Empty;
                if (codeLanguage == CodeLanguage.VBNet)
                    commentMask = @"'";
                else
                    commentMask = @"///";

                foreach (string reference in references)
                {
                    string refLine = string.Format("{0}addref<{1}>", commentMask, reference);

                    if (!string.IsNullOrEmpty(reference) &&
                        !originText.Contains(refLine))
                    {
                        insertRefText.AppendLine(refLine);
                    }
                }

                scriptText.Replace("\n", "\r\n");
                scriptText.Insert(0, insertRefText);

                //Create new script file if needed
                if ((codeFileName.Length <= 0) || (fileType == FileType.New))
                {
                    saveCodeFileDialog.FileName = codeFileName;

                    if (codeLanguage == CodeLanguage.VBNet)
                        saveCodeFileDialog.FilterIndex = 2;
                    else
                        saveCodeFileDialog.FilterIndex = 1;

                    if (saveCodeFileDialog.ShowDialog() != DialogResult.OK)
                        return;

                    codeFileName = saveCodeFileDialog.FileName;
                }

                //Save script
                using (StreamWriter writer = new StreamWriter(codeFileName))
                {
                    writer.Write(scriptText);
                }

                this.Text = codeFileName.Remove(0, codeFileName.LastIndexOf('\\') + 1);

                IsSaved = true;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Properties.Resources.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        /// <summary>
        /// Save stored script
        /// </summary>
        private void SaveAsStored()
        {
            try
            {
                IsSaved = false;
                SaveFile(FileType.New);
                if (IsSaved == true)
                {
                    if (Settings.Default.storedScripts == null)
                    {
                        Settings.Default.storedScripts = new StringCollection();
                    }

                    if (Settings.Default.startupScripts == null)
                    {
                        Settings.Default.startupScripts = new StringCollection();
                    }

                    if (!Settings.Default.storedScripts.Contains(codeFileName) &&
                        !Settings.Default.startupScripts.Contains(codeFileName))
                    {
                        Settings.Default.storedScripts.Add(codeFileName);
                        Settings.Default.Save();
                    }

                    Close();

                    MLManageScripts scrManager = new MLManageScripts(codeFileName);
                    scrManager.MainForm = mainForm;
                    scrManager.ShowDialog();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Properties.Resources.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        #endregion        
        
        #region Other methods

        /// <summary>
        /// Get coursor position in code box and set lineNumber and colNumber lables
        /// </summary>
        private void GetCoursorPosition()
        {
            int selectionStart = codeBox.SelectionStart;
            int line = codeBox.GetLineFromCharIndex(selectionStart);
            int col = selectionStart - codeBox.GetFirstCharIndexFromLine(line);

            lineNumber.Text = (line + 1).ToString();
            colNumber.Text = (col + 1).ToString();
        }

        /// <summary>
        /// Set properties to SyntaxHighlightingTextBox
        /// </summary>
        private void SetSyntaxHighlighting()
        {
            //Set separators
            codeBox.Seperators.AddRange(new char[] { ' ', '\r', '\n', '\t', ',', '.', '-', '+', '(', ')', ';', '[', ']', '{', '}' });
            switch (codeLanguage)
            {
                case CodeLanguage.VBNet:
                    {
                        //Set hightlighting for VB.Net key words 
                        string[] vbnet = CodeForm.Resources.Keywords.VBNet.Split((char[])null, StringSplitOptions.RemoveEmptyEntries);
                        foreach (string vbnetkw in vbnet)
                        {
                            codeBox.HighlightDescriptors.Add(new HighlightDescriptor(vbnetkw, Color.Blue, null, DescriptorType.Word, DescriptorRecognition.WholeWord, true));
                        }

                        //Set hightlighting for VB.Net not recomended words 
                        string[] vbnetNotRecomended = CodeForm.Resources.Keywords.VBNetNotRecommend.Split((char[])null, StringSplitOptions.RemoveEmptyEntries);
                        foreach (string vbnetkw in vbnetNotRecomended)
                        {
                            codeBox.HighlightDescriptors.Add(new HighlightDescriptor(vbnetkw, Color.Blue, null, DescriptorType.Word, DescriptorRecognition.WholeWord, true));
                        }

                        //Set hightlighting for comments
                        codeBox.HighlightDescriptors.Add(new HighlightDescriptor("'", Color.Green, null, DescriptorType.ToEOL, DescriptorRecognition.StartsWith, false));
                        
                        //Set case sensetive
                        codeBox.CaseSensitive = false;
                    }
                    break;

                case CodeLanguage.CSharp:
                default:
                    {
                        //Set hightlighting for C# key words 
                        string[] csharp = CodeForm.Resources.Keywords.CSharp.Split((char[])null, StringSplitOptions.RemoveEmptyEntries);
                        foreach (string csharpkw in csharp)
                        {
                            codeBox.HighlightDescriptors.Add(new HighlightDescriptor(csharpkw, Color.Blue, null, DescriptorType.Word, DescriptorRecognition.WholeWord, true));
                        }

                        //Set hightlighting for C# context depended words 
                        string[] csharpContext = CodeForm.Resources.Keywords.CSharpContext.Split((char[])null, StringSplitOptions.RemoveEmptyEntries);
                        foreach (string csharpkw in csharpContext)
                        {
                            codeBox.HighlightDescriptors.Add(new HighlightDescriptor(csharpkw, Color.Blue, null, DescriptorType.Word, DescriptorRecognition.WholeWord, true));
                        }

                        //Set hightlighting for comments
                        codeBox.HighlightDescriptors.Add(new HighlightDescriptor("/*", "*/", Color.Green, null, DescriptorType.ToCloseToken, DescriptorRecognition.StartsWith, false));
                        codeBox.HighlightDescriptors.Add(new HighlightDescriptor("//", Color.Green, null, DescriptorType.ToEOL, DescriptorRecognition.StartsWith, false));
                        
                        //Set case sensetive
                        codeBox.CaseSensitive = true;
                    }
                    break;
            }
            //String in Red
            codeBox.HighlightDescriptors.Add(new HighlightDescriptor(@"""", @"""", Color.Red, null, DescriptorType.ToCloseToken, DescriptorRecognition.StartsWith, false));
            codeBox.HighlightDescriptors.Add(new HighlightDescriptor(@"@""", @"""", Color.Red, null, DescriptorType.ToCloseToken, DescriptorRecognition.StartsWith, false));
        }

        /// <summary>
        /// Show error on output box double click
        /// </summary>
        private void ShowError()
        {
            int line = 0;
            int column = 0;
            
            int cursorLine = outputBox.GetLineFromCharIndex(outputBox.SelectionStart);
            StringBuilder buffer = new StringBuilder(256);
            SendMessage_Ex(outputBox.Handle, EM_GETLINE, cursorLine, buffer);
            string errortext = buffer.ToString();

            Regex regex = new Regex(@"(Line: (?<line>\d+), Column: (?<column>\d+))");
            Match match = regex.Match(errortext);

            if (match.Success)
            {
                line = Convert.ToInt32(match.Groups["line"].Value);
                column = Convert.ToInt32(match.Groups["column"].Value);
                if (column == 0)
                    column = 1;
                if (line == 0)
                    line = 1;
                codeBox.Focus();
                codeBox.SelectionStart = codeBox.GetFirstCharIndexFromLine(line - 1) + column - 1;
            }
        }

        /// <summary>
        /// External method to get line by its number
        /// </summary>
        /// <param name="hwnd">Current handle</param>
        /// <param name="wMsg">What to do</param>
        /// <param name="wParam">Line number</param>
        /// <param name="lParam">Buffer for line</param>
        /// <returns>Result</returns>
        [System.Runtime.InteropServices.DllImport("user32.dll", EntryPoint = "SendMessageA")]
        private static extern int SendMessage_Ex(IntPtr hwnd, int wMsg, int wParam, StringBuilder lParam);

        /// <summary>
        /// Lock and Unlock Buttons
        /// </summary>
        /// <param name="flag"></param>
        private void LockButtons(bool flag)
        {
            RunButton.Enabled = flag;
            CompileButton.Enabled = flag;
            StopButton.Enabled = !flag;

            runMenuItem.Enabled = flag;
            compileMenuItem.Enabled = flag;
            compileHideMenuItem.Enabled = flag;
            stopMenuItem.Enabled = !flag;

            codeBox.ReadOnly = !flag;
        }
        
        /// <summary>
        /// Added references
        /// </summary>
        /// <returns></returns>
        private StringCollection References()
        {
            StringCollection references = new StringCollection();

            foreach (DataGridViewRow refRow in referencesGrid.Rows)
            {
                try
                {
                    string refName = refRow.Cells[0].Value as string;
                    if (refName != null && refName.Length >= 0)
                        references.Add(refName);
                }
                catch (Exception ex)
                {
                    throw new NotImplementedException(ex.Message, ex.InnerException);
                }
            }

            return references;
        }

        /// <summary>
        /// WriteLine in outputbox
        /// </summary>
        /// <param name="message"></param>
        public void WriteLine(string message)
        {
            Write(string.Format("{0}\r\n", message));
        }

        /// <summary>
        /// Write in outputbox
        /// </summary>
        /// <param name="message"></param>
        public void Write(string message)
        {
            if (this.outputBox.InvokeRequired)
            {
                MultiThreadWrite writer = new MultiThreadWrite(WriteToOutput);
                this.Invoke(writer, message);
            }
            else
            {
                
                WriteToOutput(message);
            }
            Application.DoEvents();
        }

        /// <summary>
        /// Write in outputBox
        /// </summary>
        /// <param name="s"></param>
        void WriteToOutput(string s)
        {
            outputBox.AppendText(s);
        }

        /// <summary>
        /// Clear outputbox
        /// </summary>
        void OutputClear()
        {
            outputBox.Clear();
        }

        /// <summary>
        /// Show error messagebox
        /// </summary>
        /// <param name="text"></param>
        private void ShowError(string text)
        {
            MessageBox.Show(text, Properties.Resources.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
        }

        #endregion
        
        #endregion
    }
}